import { MenusService } from './../menus/menus.service';
import { IdsDto } from '@/common/dto/ids.dto';
import { hashPassword } from '@/common/utils/bcrypt';
import {
  queryBuilderAndWhereEQ,
  queryBuilderAndWhereLike,
} from '@/common/utils/db.andwhere';
import { pick } from '@/common/utils/tools';
import { BadRequestException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { plainToInstance } from 'class-transformer';
import { Request } from 'express';
import { In, Repository } from 'typeorm';
import { SysRole } from '../roles/entities/role.entity';
import { CreateUserDto } from './dto/create-user.dto';
import { ResultUserConverterDto } from './dto/result-converter.dto';
import { SearchUserDto } from './dto/search-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { SysUser } from './entities/user.entity';
import { InfoInterface } from './interface/user.interface';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(SysUser) private userRepository: Repository<SysUser>,
    @InjectRepository(SysRole) private roleRepository: Repository<SysRole>,
    private readonly menusService: MenusService,
  ) {}
  async create(createUserDto: CreateUserDto) {
    const roles = await this.roleRepository.find({
      where: { id: In(createUserDto.roleIds) },
    });
    createUserDto.password = await hashPassword('123456');
    createUserDto.sysRoles = roles;
    return this.userRepository.save(plainToInstance(SysUser, createUserDto));
  }

  async findAll(query: SearchUserDto) {
    const page = query.pageNum || 1;
    const limit = query.pageSize || 10;
    let queryBuilder = this.userRepository
      .createQueryBuilder('user')
      .where('1=1');

    const likeProps = {
      'user.username': query.keywords,
    };
    queryBuilder = queryBuilderAndWhereLike(queryBuilder, likeProps);
    const eqProps = {
      'user.status': query.status,
    };
    queryBuilder = queryBuilderAndWhereEQ(queryBuilder, eqProps);
    const [data, count] = await queryBuilder
      .skip((page - 1) * limit)
      .take(limit)
      .getManyAndCount();

    return {
      list: plainToInstance(ResultUserConverterDto, data),
      total: count,
    };
  }

  async findOne(id: string) {
    const user = await this.userRepository.findOne({
      where: { id },
      relations: {
        sysRoles: true,
      },
    });
    if (!user) return null;
    user.roleIds = user.sysRoles.map((item) => item.id);

    return plainToInstance(SysUser, user);
  }

  async findOneByUsername(username: string) {
    const user = await this.userRepository.findOne({
      where: { username },
      relations: {
        sysRoles: true,
        dept: true,
      },
    });
    if (!user) return null;
    user.roleIds = user.sysRoles.map((item) => item.id);
    return plainToInstance(SysUser, user);
  }

  async update(id: string, updateUserDto: UpdateUserDto) {
    const user = await this.userRepository.findOne({ where: { id } });
    if (!user) throw new BadRequestException('用户不存在');
    if (updateUserDto.roleIds) {
      const roles = await this.roleRepository.find({
        where: { id: In(updateUserDto.roleIds) },
      });
      updateUserDto.sysRoles = roles;
    }

    // userTmpe.id = id; // 带上id才会执行修改
    const userTmpe = this.userRepository.merge(
      user,
      plainToInstance(SysUser, updateUserDto),
    );

    return this.userRepository.save(userTmpe);
  }

  remove(id: IdsDto) {
    return this.userRepository.softDelete(id.ids.split(','));
  }

  async getOptions() {
    const users = await this.userRepository.find();
    return users.map((item) => {
      return {
        label: item.username,
        value: item.id,
        tag: '',
        children: [],
      };
    });
  }

  async resetPassword(id: string, password: string) {
    const user = await this.findOne(id);
    if (!user) throw new BadRequestException('用户不存在');
    user.password = await hashPassword(password);
    await this.userRepository.save(user);
    return '操作成功';
  }

  getProfile(req: Request) {
    const info = pick(
      req.user,
      'avatar',
      'createTime',
      'deptName',
      'email',
      'gender',
      'id',
      'mobile',
      'nickname',
      'roleNames',
      'username',
      'deptName',
      'roleNames',
    );

    return info;
  }

  async whoami(req: Request) {
    const {
      id: userId,
      username,
      nickname,
      avatar,
      authorities,
      roleIds,
    } = req.user as SysUser;

    const info: InfoInterface = {
      userId,
      username,
      nickname,
      avatar,
      roles: authorities,
      perms: [],
    };

    const perms = await this.menusService.buildRoutesByMenu(roleIds, true);
    info.perms = perms.map((item) => item.perm);

    return info;
  }
}
